package ru.amse.stroganova.ui;

import java.util.LinkedList;
import java.util.List;

import ru.amse.stroganova.ui.command.Command;

/**
 * This class represents implementation of buffer for undo/redo with restricted capacity.
 * 
 * @author Dasha Stroganova
 *
 */
public class UndoBuffer {

	private final List<Command> undoCommands;

	private final List<Command> redoCommands;

	private final int capacity;

	/**
	 * Creates an empty undo buffer with given capacity.
	 * 
	 * @param capacity
	 *            capacity
	 * 
	 */
	public UndoBuffer(int capacity) {
		undoCommands = new LinkedList<Command>();
		redoCommands = new LinkedList<Command>();
		this.capacity = capacity;
	}

	/**
	 * Pushes new command to this buffer.
	 * 
	 * @param command
	 *            command
	 */
	public void pushCommand(Command command) {
		redoCommands.clear();
		if (undoCommands.size() == capacity) {
			undoCommands.remove(0);
		}
		undoCommands.add(command);
	}

	/**
	 * Clears this buffer.
	 *
	 */
	public void clear() {
		undoCommands.clear();
		redoCommands.clear();
	}
	
	/**
	 * Performs undo.
	 * 
	 */
	public void undo() {
		if (undoCommands.size() > 0) {
			Command command = undoCommands.remove(undoCommands.size() - 1);
			redoCommands.add(command);
			command.undo();
		}
	}

	/**
	 * Performs redo.
	 * 
	 */
	public void redo() {
		if (redoCommands.size() > 0) {
			Command command = redoCommands.remove(redoCommands.size() - 1);
			undoCommands.add(command);
			command.execute();
		}
	}

	/**
	 * Checks whether there are command for undoing.
	 * 
	 * @return true if there are; false otherwise
	 */
	public boolean hasUndo() {
		return (undoCommands.size() > 0);
	}

	/**
	 * Checks whether there are command for redoing.
	 * 
	 * @return true if there are; false otherwise
	 */
	public boolean hasRedo() {
		return (redoCommands.size() > 0);
	}
}
